class_name Chunk
extends RefCounted


const dir:Array[Vector3] = [
	Vector3(0,1,0),
	Vector3(-1,0,0),
	Vector3(0,0,-1),
	Vector3(1,0,0),
	Vector3(0,0,1),
	Vector3(0,-1,0)
] 

var chunk_pos: Vector2i = Vector2i.ZERO
var world_pos: Vector2
var sections: Array[Section]


func generate_init() -> void:
	for i in int(Data.chunk_settings["height"]):
		sections.push_back(Section.new())
		sections[-1].bottom_height = Data.section_size*i
	generate_base_terrain()

func generate_base_terrain():
	#var height = int(Data.chunk_settings["height"])*Data.section_size
	var heights:Array=[]
	for y in Data.section_size:
		for x in Data.section_size:
			var height = 96+64*Data.noise.get_noise_2d(x+world_pos.x,y+world_pos.y)
			while height>=0:
				set_inner_block(Vector3(x,height,y),1)
				height = height - 1
	for y in Data.section_size:
		for x in Data.section_size:
			var height = 96
			while height>=0:
				if get_inner_block(Vector3(x,height,y))==0:
					set_inner_block(Vector3(x,height,y),2)
				else:
					break
				height = height - 1
	for i in sections:
		i.update_empty()

func build_mesh():
	for i in sections:
		if i.empty:
			continue
		else:
			_build_mesh(i)

func set_inner_block(p_pos:Vector3,p_block_type:int):
	var section_id :int    = int(p_pos.y / Data.section_size)
	var inner_pos :Vector3 = p_pos
	inner_pos.y = int(p_pos.y-section_id*Data.section_size)
	sections[section_id].set_inner_block(inner_pos,p_block_type)

func get_inner_block(p_pos:Vector3):
	var section_id :int    = int(p_pos.y / Data.section_size)
	var inner_pos :Vector3 = p_pos
	inner_pos.y = int(p_pos.y-section_id*Data.section_size)
	return sections[section_id].get_inner_block(inner_pos)

func _build_mesh(p_section:Section):
	if p_section.empty:
		return
	var vertex_s:PackedVector3Array
	var indice_s:PackedInt32Array
	var uv_s    :PackedVector2Array
	
	var f_vertex_s:PackedVector3Array
	var f_indice_s:PackedInt32Array
	var f_uv_s    :PackedVector2Array
	for x in Data.section_size:
		for y in Data.section_size:
			for z in Data.section_size:
				var block_world_pos:Vector3=Vector3(x,y,z)+Vector3(world_pos.x,p_section.bottom_height,world_pos.y)
				var block_type:int=p_section.get_inner_block(Vector3(x,y,z))
				if block_type == 0:
					continue
				var mesh_arr = Tools.block_data_base.get_block_mesh(block_type)
				if block_type==1:
					for j in 6:
						if Data.get_block(block_world_pos+dir[j])==1:
							continue
						var v_size = vertex_s.size()
						for i in mesh_arr[0][j]:
							indice_s.push_back(i+v_size)
						for i in mesh_arr[1][j]:
							vertex_s.push_back(i+block_world_pos)
						for i in mesh_arr[2][j]:
							uv_s.push_back(i)
				if block_type==2:
					for j in 6:
						if Data.get_block(block_world_pos+dir[j])==2:
							continue
						var v_size = f_vertex_s.size()
						for i in mesh_arr[0][j]:
							f_indice_s.push_back(i+v_size)
						for i in mesh_arr[1][j]:
							f_vertex_s.push_back(i+block_world_pos)
						for i in mesh_arr[2][j]:
							f_uv_s.push_back(i)
	if !vertex_s.is_empty():
		var array_data:Array
		array_data.resize(13)
		array_data[Mesh.ARRAY_VERTEX] = vertex_s
		array_data[Mesh.ARRAY_TEX_UV] = uv_s
		array_data[Mesh.ARRAY_INDEX]  = indice_s
		var array_mesh: ArrayMesh = ArrayMesh.new()
		array_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES,array_data)
		var mi :MeshInstance3D = MeshInstance3D.new()
		mi.mesh = array_mesh
		mi.set_surface_override_material(0,preload("res://assets/material/opaque/opaque.tres"))
		Main.map_root_node.add_child(mi)
		mi.owner = mi.get_parent()
		p_section.mesh_node = mi
	if !f_vertex_s.is_empty():
		var array_data:Array
		array_data.resize(13)
		array_data[Mesh.ARRAY_VERTEX] = f_vertex_s
		array_data[Mesh.ARRAY_TEX_UV] = f_uv_s
		array_data[Mesh.ARRAY_INDEX]  = f_indice_s
		var array_mesh: ArrayMesh = ArrayMesh.new()
		array_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES,array_data)
		var mi :MeshInstance3D = MeshInstance3D.new()
		mi.mesh = array_mesh
		mi.set_surface_override_material(0,preload("res://assets/material/float/float.tres"))
		Main.map_root_node.add_child(mi)
		mi.owner = mi.get_parent()
		p_section.mesh_node = mi
